package org.example.cmw;

import com.sun.management.OperatingSystemMXBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.management.ManagementFactory;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Configuration
@ConfigurationProperties(prefix = "cm")
class CMProperties {
    private Cpu cpu = new Cpu();
    private Memory memory = new Memory();

    public Cpu getCpu () {
        return cpu;
    }

    public Memory getMemory () {
        return memory;
    }

    public static class Cpu {
        private double target;          // 目标 CPU 占用 0~1
        private double fluctuation;     // 浮动比例
        private int adjustIntervalMs = 100;
        private boolean flag;

        public double getTarget () {
            return target;
        }

        public void setTarget (double target) {
            this.target = target;
        }

        public double getFluctuation () {
            return fluctuation;
        }

        public void setFluctuation (double fluctuation) {
            this.fluctuation = fluctuation;
        }

        public int getAdjustIntervalMs () {
            return adjustIntervalMs;
        }

        public void setAdjustIntervalMs (int adjustIntervalMs) {
            this.adjustIntervalMs = adjustIntervalMs;
        }

        public boolean isFlag () {
            return flag;
        }

        public void setFlag (boolean flag) {
            this.flag = flag;
        }
    }

    public static class Memory {
        private double target;          // 系统内存目标占用比例 0~1
        private double fluctuation;     // 浮动比例
        private int adjustIntervalMs = 500;
        private boolean flag;

        public double getTarget () {
            return target;
        }

        public void setTarget (double target) {
            this.target = target;
        }

        public double getFluctuation () {
            return fluctuation;
        }

        public void setFluctuation (double fluctuation) {
            this.fluctuation = fluctuation;
        }

        public int getAdjustIntervalMs () {
            return adjustIntervalMs;
        }

        public void setAdjustIntervalMs (int adjustIntervalMs) {
            this.adjustIntervalMs = adjustIntervalMs;
        }

        public boolean isFlag () {
            return flag;
        }

        public void setFlag (boolean flag) {
            this.flag = flag;
        }
    }
}

@Component
public class CMService {

    private final CMProperties properties;
    private final ExecutorService executor = Executors.newCachedThreadPool();
    private final Random random = new Random();
    private final OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
    private final int cores = Runtime.getRuntime()
            .availableProcessors();

    // private final byte[][] memoryHolder = new byte[1024][]; // 用于系统内存占用

    private final ByteBuffer[] memoryHolder;

    public CMService (CMProperties properties) {
        this.properties = properties;
        System.out.println("CPU 核数: " + cores);

        long totalMemMB = osBean.getTotalPhysicalMemorySize() / (1024 * 1024);
        System.out.println("系统总内存: " + totalMemMB + " MB");

        int blockSizeMB = 10;
        double usageRatio = properties.getMemory()
                .getTarget() + properties.getMemory()
                .getFluctuation();
        int maxBlocks = (int) ((totalMemMB / blockSizeMB) * usageRatio);

        memoryHolder = new ByteBuffer[maxBlocks];
        System.out.println("内部指定最大 Direct Memory 块数: " + maxBlocks);

    }

    @PostConstruct
    public void start () {
        if (properties.getCpu().isFlag()) startCpuTask();
         startMemoryTask();
        System.out.println(" 系统 CPU & 内存控制服务已启动");
    }

    private void startCpuTask () {
        for (int i = 0; i < cores; i++) {
            executor.submit(() -> {
                while (true) {
                    try {
                        double target = properties.getCpu()
                                .getTarget();
                        double fluctuation = properties.getCpu()
                                .getFluctuation();
                        double factor = 1 + (random.nextDouble() * 2 - 1) * fluctuation;
                        double usage = Math.min(target * factor, 1.0);

                        long interval = properties.getCpu()
                                .getAdjustIntervalMs();
                        long workTime = (long) (interval * usage);
                        long idleTime = interval - workTime;

                        long start = System.currentTimeMillis();
                        while (System.currentTimeMillis() - start < workTime) {
                            double x = Math.random() * Math.random();
                        }
                        if (idleTime > 0) Thread.sleep(idleTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    private void startMemoryTask () {
        executor.submit(() -> {
            int blockSizeMB = 10; // 每块 10MB
            while (true) {
                try {
                    long totalMemMB = osBean.getTotalPhysicalMemorySize() / (1024 * 1024);
                    long freeMemMB = osBean.getFreePhysicalMemorySize() / (1024 * 1024);
                    long usedMemMB = totalMemMB - freeMemMB;
                    double usedRatio = usedMemMB / (double) totalMemMB;

                    // 内存控制
                    if (properties.getMemory().isFlag()) {
                        double target = properties.getMemory()
                                .getTarget();
                        double fluctuation = properties.getMemory()
                                .getFluctuation();

                        int diffBlocks = (int) ((target - usedRatio) * totalMemMB / blockSizeMB);
                        diffBlocks = Math.max(-3, Math.min(3, diffBlocks));

                        // 分配 DirectByteBuffer
                        for (int i = 0; i < diffBlocks; i++) {
                            for (int j = 0; j < memoryHolder.length; j++) {
                                if (memoryHolder[j] == null) {
                                    try {
                                        memoryHolder[j] = ByteBuffer.allocateDirect(blockSizeMB * 1024 * 1024);
                                    } catch (OutOfMemoryError e) {
                                        System.err.println("️ 无法再分配更多系统内存了");
                                        break;
                                    }
                                    break;
                                }
                            }
                        }

                        // 释放 DirectByteBuffer
                        for (int i = 0; i < -diffBlocks; i++) {
                            for (int j = memoryHolder.length - 1; j >= 0; j--) {
                                if (memoryHolder[j] != null) {
                                    memoryHolder[j] = null;
                                    break;
                                }
                            }
                        }
                    }

                    System.out.println(String.format("CPU Used: %.2f%% | 系统内存使用: %d MB / %d MB (%.2f%%)",
                                                     osBean.getSystemCpuLoad() * 100, usedMemMB, totalMemMB, usedRatio * 100));

                    TimeUnit.MILLISECONDS.sleep(properties.getMemory()
                                                        .getAdjustIntervalMs());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
